/*
 *  AbstractClasses.h
 *  AKCPP
 *
 *  Created by Ben Chen on 1/22/08.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */

#ifndef _AKCPPBASE_H
#define _AKCPPBASE_H

#pragma once

#include <vector>
using namespace std;

/**
 *	Specify the basic operations used to record the state of the game.
 */
class AKStateRecorder
{
protected:
	AKStateRecorder();
public:
	virtual ~AKStateRecorder();
	
	/**
	 *	Make the recorder reflect the initial state, as that in the beginning of a game.
	 */
	virtual void backToInitialState() = 0;
	
	/**
	 *	Perform a move on the recorder.
	 *	\param[in] newMove The information of the new move.
	 *	\return true if suceeded, false otherwise (e.g. the move is not permitted).
	 */
	virtual bool performMove(const AKMove newMove) = 0;
	
	/**
	 *	If can undo the last move.
	 *	\return true if controller can undo the last move, false otherwise.
	 */
	virtual bool canUndo() = 0;
	
	/**
	 *	Undo last move.
	 *	Note: Redo can be done by performMove(), so no need for a separated redo method.
	 *	\return true if undone successfully, false otherwise, i.e., cannot redo.
	 */
	virtual bool undo() = 0;
};

/**
 *	A player has the power to record the state of the game and also calculate next move based on that. 
 */
class AKCPPPlayer : public AKStateRecorder
{
	typedef AKStateRecorder PARENT;
protected:
	/**
	 *	Constructor.
	 *	\param[in] aSide The side of the player, which cannot be changed once created.
	 */
	AKCPPPlayer(AKSideIndex aSide, unsigned int aNumOfSides);
	
public:
	virtual	~AKCPPPlayer();
	
	/**
	 *	Get the next move based on the current state.
	 *	\return AKZeroMove if cannot generate next move (e.g. winning state reached, or other players should go instead), 
	 *	otherwise the next move.
	 */
	virtual const AKMove getBestMove() = 0;

	/**
	 *	This method is used in case the move returned by \p getBestMove() is not permitted by AKStateMaintainer.
	 *	Every call to this function should return a different move. If two conjunctive calls return the same move,
	 *  another move will be generated by AKStateMaintainer.
	 *	Warning: This method should be only called after the call to getBestMove() returns a none-permitted move.
	 */
	virtual const AKMove getAlternativeMove() = 0;
	
	/**
	 *	Get the side of the player.
	 *	Once created, the side of a player cannot be changed.
	 *	\return the side index of the player, which is zero-based, should be no more than getNumOfSide() - 1 
	 *	in which AKCPPBasicInfoProvider::getNumOfSide() is returned by a corresponding AKCPPBasicInfoProvider object.
	 */
	virtual const AKSideIndex getSide();
	
protected:
	AKSideIndex side;
	unsigned int numOfSides;
};

/**
 *	State maintainer.
 *	State maintainer not only records the game, but also tells other information like who is the next player and if the game is over, etc.
 */
class AKCPPStateMaintainer : public AKStateRecorder
{
	typedef AKStateRecorder PARENT;
protected:
	AKCPPStateMaintainer(unsigned int aNumOfSides);
	
public:
	/**
	 *	Return the pieces that have been created during last turn.
	 *	If only backToInitialState() was called prior to this method, it should retain all pieces on the board.
	 */
	virtual const vector<AKPiece>*	getCreatedPieces() = 0;

	/**
	 *	Return the pieces that have been eliminated during last turn.
	 */
	virtual const vector<AKPiece>*	getElminatedPieces() = 0;

	/**
	 *	Return the pieces that have been moved during last turn in the form of AKMoves
	 */
	virtual const vector<AKMove>*	getMovedPieces() = 0;

	/**
	 *	Get all pieces on the board.
	 *	\return a vector containing all the pieces on the board.
	 */
	virtual const vector<AKPiece>*	getAllPieces() = 0;

	virtual ~AKCPPStateMaintainer();
	
	/**
	 *	Get the side index of the next player.
	 *	At initial state this method returns the side index of the first player; at winning state, this method return NSNotFound.
	 *	\return NSNotFound if no player can make any move, otherwise the index of the next player's side.
	 */
	virtual const AKSideIndex getNextPlayerSide() = 0;

	/**
	 *	Get an alternative move for the next player.
	 *	This method is needed that a player can only generate moves that are not permitted by the state maintainer.
	 */
	virtual const AKMove getAlternativeMoveForNextPlayer() = 0;
	
	/**
	 *	Get side indices of winners.
	 *	When reached a draw state, this method should return all the players.
	 *	\return a vector containing all players.
	 */
	virtual const vector<AKSideIndex>*	getWinners() = 0;
	
	// State info
	
	/**
	 *	Get pieces of the next player's side that can be placed at a cell.
	 *	For example, in the game of Tic-Tac-Toe, every move is made by creating a new piece and place it on the board.
	 *	\param[in] cellIndex The index of the specified cell.
	 *	\return a vector containing all the pieces that can be placed on a cell.
	 */
	virtual const vector<AKPiece>*		getPlaceablePiecesAtCell(const AKCellIndex) = 0;
	
	/**
	 *	Get indices of cells that can be reached by moving \c piece.
	 *	\param[in] piece The specified piece.
	 *	\return a vector containing the cell indices can be reached by \p piece.
	 */
	virtual const vector<AKCellIndex>*	getReachableCellsForPiece(const AKPiece piece) = 0;
	
	/**
	 *	Returns the piece that is standing at the specified cell that can be moved to somewhere else.
	 *	\return AKZeroPiece if no such piece is found.
	 */
	virtual const AKPiece getMoveablePieceAtCell(const AKCellIndex cell) = 0;
private:
	unsigned int numOfSides;
};

/**
 *	Provides basic information of a game.
 */
class AKCPPBasicInfoProvider
{
protected:
	AKCPPBasicInfoProvider();
	
public:
	virtual ~AKCPPBasicInfoProvider();
	
	/**
	 *	Get number of cells on the board.
	 *	\return Number of cells on the board.
	 */
	virtual unsigned int getNumOfCells() = 0;
	
	/**
	 *	Get max number of sides, i.e., at most, how many players can play this game simultaneously.
	 *	\return max number of sides, which should be greater than or equal to the value returned by AKCPPBasicInfoProvider::getMinNumOfSide().
	 */
	virtual unsigned int getMaxNumOfSide() = 0;
	
	/**
	 *	Get min number of sides, i.e., at least, how many players can play this game simultaneously.
	 *	\return min number of sides, which should be smaller than or equal to the value returned by AKCPPBasicInfoProvider::getMaxNumOfSide().
	 */
	virtual unsigned int getMinNumOfSide() = 0;
	
	/**
	 *	Get the number of pieces of a specified side.
	 *	Most games have same number of pieces for every side.
	 *	\param[in] sideIndex The index of specified side.
	 *	\return Number of pieces for specified side, or 0 if specified side is not supported.
	 */
	virtual unsigned int getNumOfPiecesForSide(const AKSideIndex sideIndex) = 0;
};

#endif // _AKCPPBASE_H
